package cn.genmer.test.security;

import org.locationtech.proj4j.*;

import java.util.ArrayList;
import java.util.List;

public class PolygonAreaCalculatorV1 {
 // 2736527 - 2730891.91
    // 952863299 - 950848522.16
    // 2736527 - 2730863.88
    // 1918930173 - 1915164147.77





    /**
     * 第1组	2,736,527	2,730,891.91	5,635.09  0.206%
     * 第2组	952,863,299	950,848,522.16	2,014,776.84	0.211%
     * 第3组	2,736,527	2,730,863.88	5,663.12	0.207%
     */
    public static void main(String[] args) {
        String input = "[[116.727356,40.429554],[116.410703,39.897555],[116.402292,39.892353],[116.389846,39.891365],[116.384876,39.828065],[116.43665,39.07919],[116.260017,39.845009],[115.3443,39.27177],[116.19974,39.891686],[116.204427,39.941013],[115.157544,40.539437],[116.294843,39.9868]]";
        long l = System.currentTimeMillis();
        double area = calculatePolygonArea(input);
        System.out.printf("多边形面积：%.2f 平方米, 计算耗时：%s ms", area,  System.currentTimeMillis() - l);
    }

    public static double calculatePolygonArea(String input) {
        // 1. 解析输入字符串
        List<Coordinate> latLonCoordinates = parseCoordinates(input);
        if (latLonCoordinates.size() < 3) {
            throw new IllegalArgumentException("至少需要3个点构成多边形");
        }

        // 2. 确定UTM投影带号
        Coordinate firstPoint = latLonCoordinates.get(0);
        int utmZone = (int) Math.floor((firstPoint.lon + 180) / 6) + 1;
        String hemisphere = (firstPoint.lat >= 0) ? "north" : "south";
        String targetCrsCode = "EPSG:326" + utmZone; // 北半球使用326XX，南半球使用327XX
        if ("south".equals(hemisphere)) {
            targetCrsCode = "EPSG:327" + utmZone;
        }

        // 3. 坐标系转换
        List<Point> utmPoints = convertToUTM(latLonCoordinates, targetCrsCode);

        // 4. 计算平面面积
        return calculatePlanarArea(utmPoints);
    }

    // 解析坐标字符串
    private static List<Coordinate> parseCoordinates(String input) {
        List<Coordinate> coordinates = new ArrayList<>();
        // 彻底清洗字符串（移除所有非数字、小数点、逗号、负号）
        String cleaned = input.replaceAll("[^\\d.,-]", "");
        String[] parts = cleaned.split(",");

        if (parts.length % 2 != 0) {
            throw new IllegalArgumentException("坐标数量应为偶数");
        }

        try {
            for (int i = 0; i < parts.length; i += 2) {
                double lon = Double.parseDouble(parts[i].trim());
                double lat = Double.parseDouble(parts[i + 1].trim());
                coordinates.add(new Coordinate(lon, lat));
            }
        } catch (NumberFormatException e) {
            // String errorPair = "索引 " + (i/2) + ": [" + parts[i] + ", " + parts[i+1] + "]";
            throw new IllegalArgumentException("坐标解析失败! ");
        }
        return coordinates;
    }
    // 转换为UTM坐标系
    private static List<Point> convertToUTM(List<Coordinate> coordinates, String targetCrsCode) {
        CRSFactory crsFactory = new CRSFactory();
        CoordinateTransformFactory ctFactory = new CoordinateTransformFactory();
        List<Point> utmPoints = new ArrayList<>();

        try {
            CoordinateReferenceSystem srcCrs = crsFactory.createFromName("EPSG:4326");
            CoordinateReferenceSystem tgtCrs = crsFactory.createFromName(targetCrsCode);
            CoordinateTransform transform = ctFactory.createTransform(srcCrs, tgtCrs);

            for (Coordinate coord : coordinates) {
                ProjCoordinate src = new ProjCoordinate(coord.lon, coord.lat);
                ProjCoordinate dest = new ProjCoordinate();
                transform.transform(src, dest);
                utmPoints.add(new Point(dest.x, dest.y));
            }
        } catch (Exception e) {
            throw new RuntimeException("坐标系转换失败: " + e.getMessage());
        }
        return utmPoints;
    }

    // 使用Shoelace公式计算平面面积
    private static double calculatePlanarArea(List<Point> points) {
        double area = 0.0;
        int n = points.size();
        
        for (int i = 0; i < n; i++) {
            Point current = points.get(i);
            Point next = points.get((i + 1) % n);
            area += (current.x * next.y) - (next.x * current.y);
        }
        
        return Math.abs(area) / 2.0;
    }

    // 辅助类
    static class Coordinate {
        double lon;
        double lat;

        Coordinate(double lon, double lat) {
            this.lon = lon;
            this.lat = lat;
        }
    }

    static class Point {
        double x;
        double y;

        Point(double x, double y) {
            this.x = x;
            this.y = y;
        }
    }
}
